/*
   FieldVis - A Tool for Visualizing Astrophysical Magnetohydrodynamic Flow
   
   Copyright (C) 2006 - 2008     FieldVis Development Team
  
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
  
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
  
   You should have received a copy of the GNU General Public License along
   with this program; if not, write to the Free Software Foundation, Inc.,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

   File        : DataSet.cpp
   Author      : Jeremy Moc  (mocj@msi.umn.edu)

   Description : Data structures to hold the file data. See DataSet.h for a
                 further description.
*/

#include "DataSet.h"

///////////////////////////////////////////////////////////////////////////////

DataSlice::DataSlice(std::ifstream &f, const int x, const int y, const int z)
   : xSize(x)
{
   slice = new float[ x * y ];

   f.seekg( x * y * z * sizeof(float), std::ios::beg );
   f.read( (char*)slice, x * y * sizeof(float) );

   if (f.bad())
   {
      std::cerr << "Error reading data from file...." << std::endl;
   }
}


///////////////////////////////////////////////////////////////////////////////

Mutex DataSet::mutex;

DataSet::DataSet(const std::string &filename, const int x, const int y, const int z)
   : xSize(x), ySize(y), zSize(z)
{
   file.open(filename.c_str(), std::ios::in | std::ios::binary);

   if (file.bad())
   {
      std::cerr << "Error opening file: " << filename << std::endl;
   }

   file.seekg(0, std::ios::end);   
   if ( (int)(x * y * z * sizeof(float)) != file.tellg() )
   {
      std::cerr << "Size of open file: " << file.tellg()
                << "\n        should be: " << x * y * z * sizeof(float)
                << std::endl;
   }
   
   vi = new std::vector<DataSlice*>(z, static_cast<DataSlice*>(0));
}

DataSet::~DataSet()
{
   std::vector<DataSlice*>::iterator iter;
   for (iter = vi->begin(); iter != vi->end(); iter++)
   {
      delete *iter;
   }
   delete vi;
   file.close();
}

float DataSet::Get(const int x, const int y, const int z)
{
   {  // start a new scope for the Mutex
      MutexLock lock(mutex);
      if (vi->at(z) == static_cast<DataSlice*>(0))
      {
         vi->at(z) = new DataSlice(file, xSize, ySize, z);
      }
   }
   
   return ( vi->at(z)->Get(x, y) );
}

///////////////////////////////////////////////////////////////////////////////

Mutex DataSetManager::mutex;
DataSetManager DataSetManager::manager;

DataSetManager::~DataSetManager()
{
   std::map<std::string, DataSet*>::iterator iter;
   for (iter = theMap.begin(); iter != theMap.end(); iter++)
   {
      delete (iter->second);
   }
}

DataSet *DataSetManager::Manage(const std::string filename,
				const int x, const int y, const int z)
{
   std::ostringstream stream;

   stream << filename << ":" << x << ":" << y << ":" << z;

   {  // start a new scope for the Mutex
      MutexLock lock(mutex);
      if ( ! theMap.count(stream.str()))
      {
         theMap[stream.str()] = new DataSet(filename, x, y, z);
      }
   }
   
   return (theMap[stream.str()]);
}
